package com.polaris.live.common.util

import com.polaris.live.common.util.JsonUtils.readJsonArray
import com.polaris.live.common.util.JsonUtils.readJsonObject
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonReader.Token
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import okio.Buffer
import java.lang.reflect.Type
import kotlin.reflect.javaType
import kotlin.reflect.typeOf

/**
 * JsonUtils
 *
 * @author Created by lucas on 2023/11/4 10:00
 */
object JsonUtils {

    val moshi = Moshi.Builder()
        .addLast(KotlinJsonAdapterFactory())
        .build()

    /**
     * 将对象转换为json
     *
     * @param value 值
     */
    inline fun <reified T> toJson(value: T): String {
        @OptIn(ExperimentalStdlibApi::class)
        val type = typeOf<T>().javaType
        return moshi.adapter<T>(type).toJson(value)
    }

    /**
     * 将对象转换为漂亮的json
     */
    inline fun <reified T> toPrettyJson(value: T): String {
        val buffer = Buffer()
        val jsonWriter = JsonWriter.of(buffer).apply {
            indent = "    "
        }

        @OptIn(ExperimentalStdlibApi::class)
        val type = typeOf<T>().javaType
        moshi.adapter<T>(type).toJson(jsonWriter, value)

        return buffer.readUtf8()
    }

    /**
     * 根据[Type]类型解析Json为对象
     */
    inline fun <reified T> fromJson(json: String): T? {
        @OptIn(ExperimentalStdlibApi::class)
        val type = typeOf<T>().javaType
        return fromJson(json, type)
    }

    /**
     * 根据[Type]类型解析Json为对象
     */
    fun <T> fromJson(json: String, type: Type): T? {
        return try {
            moshi.adapter<T>(type).fromJson(json)
        } catch (e: JsonDataException) {
            LogExt.logE("--net", e) {
                "parse json failure: $json"
            }

            null
        }
    }

    /**
     * json字符串转换为[JsonReader]
     */
    fun toJsonReader(json: String): JsonReader = JsonReader.of(Buffer().writeUtf8(json))

    /**
     * 从json中读取一个基本类型的值
     */
    fun readPrimitiveFromJsonObject(json: String, key: String): String? {
        return readPrimitiveFromJsonObject(toJsonReader(json), key)
    }

    /**
     * 从json中读取一个基本类型的值
     */
    fun readPrimitiveFromJsonObject(jsonReader: JsonReader, key: String): String? {
        var string: String? = null
        readJsonObject(jsonReader) {
            if (name == key) {
                when (peekToken) {
                    Token.STRING -> string = getString()
                    Token.NUMBER -> string = getLong().toString()
                    Token.BOOLEAN -> string = getBoolean().toString()
                    else -> skipValue()
                }
            }
        }
        return string
    }

    /**
     * 从json中读取一个boolean
     */
    fun readBooleanFromJsonObject(json: String, key: String): Boolean? {
        return readBooleanFromJsonObject(toJsonReader(json), key)
    }

    /**
     * 从json中读取一个boolean
     */
    fun readBooleanFromJsonObject(jsonReader: JsonReader, key: String): Boolean? {
        var boolean: Boolean? = null
        readJsonObject(jsonReader) {
            if (name == key) {
                boolean = getBooleanOrNull()
            }
        }
        return boolean
    }

    /**
     * 从json中读取一个数值
     */
    fun readNumberFromJsonObject(json: String, key: String): Long? {
        return readNumberFromJsonObject(toJsonReader(json), key)
    }

    /**
     * 从json中读取一个数值
     */
    fun readNumberFromJsonObject(jsonReader: JsonReader, key: String): Long? {
        var long: Long? = null
        readJsonObject(jsonReader) {
            if (name == key) {
                long = getLongOrNull()
            }
        }
        return long
    }

    /**
     * 从json中读取一个字符串
     */
    fun readStringFromJsonObject(json: String, key: String): String? {
        return readStringFromJsonObject(toJsonReader(json), key)
    }

    /**
     * 从json中读取一个字符串
     */
    fun readStringFromJsonObject(jsonReader: JsonReader, key: String): String? {
        var string: String? = null
        readJsonObject(jsonReader) {
            if (name == key) {
                string = getStringOrNull()
            }
        }
        return string
    }

    /**
     * 解析为对象
     */
    fun readJsonObject(json: String, block: JsonObjectReaderWrapper.() -> Unit) {
        readJsonObject(toJsonReader(json), block)
    }

    /**
     * 解析为对象
     */
    fun readJsonObject(jsonReader: JsonReader, block: JsonObjectReaderWrapper.() -> Unit) {
        jsonReader.beginObject()

        while (jsonReader.hasNext()) {
            val name = jsonReader.nextName()
            val peekToken = jsonReader.peek()

            val wrapper = JsonObjectReaderWrapper(jsonReader, peekToken, name)

            block(wrapper)

            if (!wrapper.readNext) {
                jsonReader.skipValue()
            }
        }

        jsonReader.endObject()
    }

    /**
     * 解析为数组
     */
    fun readJsonArray(json: String, block: JsonArrayReaderWrapper.() -> Unit) {
        readJsonArray(toJsonReader(json), block)
    }

    /**
     * 解析为数组
     */
    fun readJsonArray(jsonReader: JsonReader, block: JsonArrayReaderWrapper.() -> Unit) {
        jsonReader.beginArray()

        var i = 0
        while (jsonReader.hasNext()) {
            val peekToken = jsonReader.peek()

            val wrapper = JsonArrayReaderWrapper(jsonReader, peekToken, i++)

            block(wrapper)

            if (!wrapper.readNext) {
                jsonReader.skipValue()
            }
        }

        jsonReader.endArray()
    }
}

abstract class AbstractJsonReaderWrapper(
    private val jsonReader: JsonReader,
    val peekToken: Token
) {

    internal var readNext: Boolean = false

    private var _nextBoolean: Boolean? = null
    private var _nextInt: Int? = null
    private var _nextLong: Long? = null
    private var _nextDouble: Double? = null
    private var _nextString: String? = null
    private var _nextObject: Boolean? = null
    private var _nextArray: Boolean? = null

    fun skipValue() {
        if (readNext) {
            return
        }

        jsonReader.skipValue()
        readNext = true
    }

    fun getBoolean(): Boolean {
        val nextBoolean = _nextBoolean
        if (nextBoolean != null) {
            return nextBoolean
        }

        return jsonReader.nextBoolean().apply {
            _nextBoolean = this
            readNext = true
        }
    }

    fun getBooleanOrNull(): Boolean? {
        return if (peekToken == Token.BOOLEAN) {
            getBoolean()
        } else {
            skipValue()
            null
        }
    }

    fun getInt(): Int {
        val nextInt = _nextInt
        if (nextInt != null) {
            return nextInt
        }

        return jsonReader.nextInt().apply {
            _nextInt = this
            readNext = true
        }
    }

    fun getIntOrNull(): Int? {
        return if (peekToken == Token.NUMBER) {
            getInt()
        } else {
            skipValue()
            null
        }
    }

    fun getLong(): Long {
        val nextLong = _nextLong
        if (nextLong != null) {
            return nextLong
        }

        return jsonReader.nextLong().apply {
            _nextLong = this
            readNext = true
        }
    }

    fun getLongOrNull(): Long? {
        return if (peekToken == Token.NUMBER) {
            getLong()
        } else {
            skipValue()
            null
        }
    }

    fun getDouble(): Double {
        val nextDouble = _nextDouble
        if (nextDouble != null) {
            return nextDouble
        }

        return jsonReader.nextDouble().apply {
            _nextDouble = this
            readNext = true
        }
    }

    fun getDoubleOrNull(): Double? {
        return if (peekToken == Token.NUMBER) {
            getDouble()
        } else {
            skipValue()
            null
        }
    }

    fun getString(): String {
        val nextString = _nextString
        if (nextString != null) {
            return nextString
        }

        return jsonReader.nextString().apply {
            _nextString = this
            readNext = true
        }
    }

    fun getStringOrNull(): String? {
        return if (peekToken == Token.STRING) {
            getString()
        } else {
            skipValue()
            null
        }
    }

    /**
     * 如果是对象，只有第一次调用会回调
     */
    fun nextObject(block: (JsonObjectReaderWrapper) -> Unit) {
        if (peekToken == Token.BEGIN_OBJECT) {
            if (_nextObject == true) {
                return
            }

            readJsonObject(jsonReader, block)
            _nextObject = true
            readNext = true
        } else {
            skipValue()
        }
    }

    /**
     * 如果是数组，只有第一次调用会回调
     */
    fun nextArray(block: (JsonArrayReaderWrapper) -> Unit) {
        if (peekToken == Token.BEGIN_ARRAY) {
            if (_nextArray == true) {
                return
            }

            readJsonArray(jsonReader, block)
            _nextArray = true
            readNext = true
        } else {
            skipValue()
        }
    }
}

class JsonObjectReaderWrapper(
    jsonReader: JsonReader,
    peekToken: Token,
    val name: String
) : AbstractJsonReaderWrapper(jsonReader, peekToken)

class JsonArrayReaderWrapper(
    jsonReader: JsonReader,
    peekToken: Token,
    val index: Int
) : AbstractJsonReaderWrapper(jsonReader, peekToken)